home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Graphics Plus
/
Graphics Plus.iso
/
msdos
/
plotting
/
pcgplots
/
cgmio.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
1992-04-24
|
39KB
|
1,395 lines
// C++ .cc file for gplot, CGM-specific I/O and parsing -*-c++-*-
// copyright Phil Andrews, Pittsburgh Supercomputing Center, 1992
// all rights reserved
#ifdef macintosh
# include <errors.h>
#endif
#include <ctype.h>
#include <stdio.h>
#include <values.h>
#include "cgm.h"
#include "cgmio.h"
#ifndef _toupper
#define _toupper(c) ((c) -'a'+'A')
#endif
////
// error call
////
extern void myError(const char *inMsg, const char *inMsg2=NULL,
int severity=1);
#ifdef macintosh
#pragma segment CIO1
#endif
// inititalization needed for some compilers
int cgmInput::beginPictureIndex = 0;
int cgmInput::endMetafileIndex = 0;
////
// basic cgm input
////
const int cgmInput::noErrors = 1;
const int cgmInput::noSep = 1<<1;
const int cgmInput::skipParen = 1<<2;
////
//initialize constants
////
void cgmInput::initialize()
{
// do we need to initialize the name array ?
if (!cgmNameArray) initNameArray();
// initialize other pointers
vdcTypeCmd = NULL;
intPrecCmd = NULL;
realPrecCmd = NULL;
indexPrecCmd = NULL;
defColrPrec.maxInt = 255;
defColrPrec.noBytes = 1;
defColrIndexPrec.maxInt = 255;
defColrIndexPrec.noBytes = 1;
colrPrecCmd = NULL;
colrIndexPrecCmd = NULL;
vdcIntPrecCmd = NULL;
defVdcIntPrecCmd = NULL;
vdcRealPrecCmd = NULL;
defVdcRealPrecCmd = NULL;
inputError = 0;
}
////
// index the metafile
////
void cgmInput::makeIndex(cgmMetafile *inMF)
{
if (!inMF->firstPic) return; // no pictures
cgmBeginPicture *myBeginPic;
cgmPicture *lastPic, *currPic = NULL;
////
// mark our spot
filePos savePos = pos();
////
// go to the beginning
goTo(inMF->start());
lastPic = inMF->firstPic;
////
// find all of the begin picture commands (already have at least first one)
int noPics = 0;
while (getCmd() && !sameCmd(cgmNameArray[endMetafileIndex])) {
if (sameCmd(cgmNameArray[beginPictureIndex])) { // begin picture
if (noPics) { // at second one, at least
myBeginPic = new cgmBeginPicture(inMF, this);
if (!currPic) lastPic->next =
new cgmPicture(inMF, this, myBeginPic, lastPic);
lastPic = lastPic->next;
}
currPic = lastPic->next;
++noPics;
} // begin picture
} // got a command
////
// go back to where we began
goTo(savePos);
}
////
// get a direct colour (R,G,B)
////
void cgmInput::getDColr(dColr &inColr)
{
// for (int i=0; i<3; ++i) inColr[i] = getCD();
for (int i=0; i<3; ++i) inColr.setValue(i, getCD());
}
////
// get a general colour
////
genColr *cgmInput::getColr(int mode, const colrValueExtent *inExtent,
const colrTable *inTable)
{
if (mode) { // r, g, b mode
int red = getCD();
int green = getCD();
int blue = getCD();
return new genColr(red, green, blue, inExtent, inTable);
} else return new genColr(getCI(), inExtent, inTable); // indexed
}
////
// get a single vdc measure
////
vdc *cgmInput::getVdc()
{
if (myVdcType()) { // real VDC
return new vdc(getVRP());
} else { // integer VDC
return new vdc(getVIP());
}
}
////
// get a set of vdc points
////
vdcPts *cgmInput::getVdcPts(int inNoPts)
{
int maxPts = inNoPts ? inNoPts : getNoPts(); // how many would we like
int ptsGot = 0;
if (myVdcType()) { // real VDC
float *floatPtr = new float[maxPts * 2]; // real vdc
while ((ptsGot < maxPts) && getPt(floatPtr + 2 * ptsGot)) ++ptsGot;
return new vdcPts(floatPtr, ptsGot);
} else { // integer VDC
int *intPtr = new int[maxPts * 2]; // integer vdc
while ((ptsGot < maxPts) && getPt(intPtr + 2 * ptsGot)) ++ptsGot;
return new vdcPts(intPtr, ptsGot);
}
}
////
// get a polygon set
////
void cgmInput::polygonSet(vdcPts* &outPts, int* &outFlags)
{
int maxPts = polygonSetSize(), ptsGot = 0;
outFlags = new int[maxPts];
if (myVdcType()) { // real VDC
float *floatPtr = new float[maxPts * 2]; // real vdc
while ((ptsGot < maxPts) && getPt(floatPtr + 2 * ptsGot)) {
outFlags[ptsGot] = getType(cgmPolygonSet::typeList,
cgmPolygonSet::typeListSize);
++ptsGot;
}
outPts = new vdcPts(floatPtr, ptsGot);
} else { // integer VDC
int *intPtr = new int[maxPts * 2]; // integer vdc
while ((ptsGot < maxPts) && getPt(intPtr + 2 * ptsGot)) {
outFlags[ptsGot] = getType(cgmPolygonSet::typeList,
cgmPolygonSet::typeListSize);
++ptsGot;
}
outPts = new vdcPts(intPtr, ptsGot);
}
}
////
// get a colour table
////
colrTable *cgmInput::getColrTable(const colrValueExtent *inExtent)
{
int startIndex = getCI();
int noEntries = getNoDColrs();
dColr tmpDColr; // temporary
colrTable *newTable = new colrTable(noEntries, inExtent, startIndex);
for (int i=0; i<noEntries; ++i) {
getDColr(tmpDColr);
newTable->addColr(tmpDColr);
}
return newTable;
}
////
// clear text input
////
// the constant values for the clear info class
////
const char clearInfo::termChar = ';'; // terminating character
const char clearInfo::termChar1 = '/';
const char clearInfo::quoteChar = '\"'; // quotation character
const char clearInfo::quoteChar1 = '\'';
const char clearInfo::sepChar = ' '; // separation character
const char clearInfo::sepChar1 = '\011';
const char clearInfo::sepChar2 = '\012';
const char clearInfo::sepChar3 = '\013';
const char clearInfo::sepChar4 = '\014';
const char clearInfo::sepChar5 = '\015';
const char clearInfo::sepChar6 = ',';
const char clearInfo::nullChar = '_'; // null character (ignored inside tokens)
const char clearInfo::nullChar1 = '$';
const char clearInfo::commentChar = '%'; // comment character
////
// the clear input class
////
// get one clear text command into memory
#if __MSDOS__
HugePt clearInput::getCmd()
#else
unsigned char *clearInput::getCmd()
#endif
{
// state of parsing
enum {normalS, quoting, spacing, commenting} myState = normalS;
int done = 0; // have we finished ?
int endFile = 0; // ran out of input
char c; // latest character
char lastQuote = 0; // last quotation character used
myLastPos = pos(); // mark our spot
bIndex = 0; // initialize buffer index
// now loop until done and still have input
#ifdef macintosh
long char_count = 1;
while (!done && !(endFile = (FSRead(frefHand,&char_count, &c) == eofErr))) {
#elif __MSDOS__
while ( !done && !(endFile = eof(frefHand))) {
read(frefHand, &c,1);
#else
while (!done && !(endFile = ((c = getc(filePtr)) == EOF))) {
#endif
switch (myState) {
case commenting: // in the middle of a comment
if (isComment(c)) myState = normalS; // end of comment
break; // else ignore input for now
case quoting: // in the middle of a quote
if (c == lastQuote) myState = normalS; // end of quote
buffer[bIndex++] = c; // in any case take input
break;
case spacing: // getting spaces
if (isSep(c)) break; // no input
else myState = normalS; // fall thru to normalS state to process c
case normalS: // normalS input mode
if (isQuote(c)) { // begin quoting
myState = quoting;
lastQuote = c;
} else if (isComment(c)) { // begin a comment
myState = commenting;
break; // no input
} else if (isTerm(c)) { // finished this command
done = 1;
} else if (isSep(c)) { // a separator
myState = spacing;
if (bIndex) { // had some real input already
c = sepChar; // standard separator character
} else break; // no leading spaces
} else if (isNull(c)) { // null character, ignore
break;
} else if (iscntrl(c)) { // control character, ignore
break;
}
else if (islower(c)) { // lower case
c = _toupper(c); // map to upper case for convenience
}
buffer[bIndex++] = c; // acceptable input
} // end of switch statement
if (bIndex >= bufferSize) { // need more memory
if (!doubleBuffer(bIndex)) {
myError("couldn't double buffer size", "aborting", 0);
return NULL;
}
}
} // end of while statement
if (endFile) return NULL; // no more input, will terminate
if (!done) { // incomplete command
bIndex = 0; // ignore this command, but continue processing
}
// normal finish
buffer[bIndex] = 0; // terminate string
return buffer; // return the parsed string
}
////
// match the incoming command name to the beginning of the buffer
////
int clearInput::same(const char *inCmd)
{
static const int caseDiff = 'A' - 'a';
int foundMatch;
for (int i=0; (i<bIndex) && inCmd[i]; ++i) {
if (buffer[i] == inCmd[i]) continue;
if ((((int)buffer[i] - inCmd[i]) == caseDiff) &&
(islower(inCmd[i]))) continue;
if (((inCmd[i] - (int) buffer[i]) == caseDiff) &&
(isupper(inCmd[i]))) continue;
return 0; // no match
}
// match if got to end of inCmd, nothing useful left in buffer
foundMatch = (!inCmd[i]) && !isalnum(buffer[i]);
if (foundMatch) { // skip over the command name
aIndex = i;
}
return foundMatch;
}
// figure out how many points we have coming
// somewhat simple minded, but should give an upper bound
int clearInput::getNoPts()
{
int noVDC = 0; long tIndex = aIndex;
enum {between, inNumber} myState = between;
while ((tIndex < bIndex) && (!isTerm(buffer[tIndex]))) { // loop thru input
if (isSep(buffer[tIndex]) || (buffer[tIndex] == '(')
|| (buffer[tIndex] == ')')) { // not in a number
myState = between; // mark state
} else if (myState == between) { // entering a number
myState = inNumber;
++noVDC;
}
++tIndex;
} // end of input
return (noVDC + 1) / 2;
}
// figure out how many points in a polygon set
int clearInput::polygonSetSize()
{
return (getNoTokens() + 2) / 3;
}
// figure out how many tokens we have coming
int clearInput::getNoTokens()
{
int noTokens = 0; long tIndex = aIndex;
enum {between, inToken} myState = between;
while ((tIndex < bIndex) && (!isTerm(buffer[tIndex]))) {
if (isSep(buffer[tIndex])) {
if (myState == inToken) {
myState = between;
}
} else if (myState == between) {
myState = inToken;
++noTokens;
}
++tIndex;
}
return noTokens;
}
////
// get an integer point
////
int clearInput::getPt(int *outArray)
{
int useParen;
while ((aIndex < bIndex) && isSep(buffer[aIndex])) ++aIndex; // skip seps
if ((useParen = (buffer[aIndex] == '('))) ++aIndex; // using parentheses
outArray[0] = getInt(); // x
outArray[1] = getInt(); // y
while ((aIndex < bIndex) && isSep(buffer[aIndex])) ++aIndex; // skip seps
if (useParen && (buffer[aIndex] == ')')) ++aIndex; // matching parenthesis
return inputError ? (inputError = 0), 0 : 1;
}
////
// get a real point
////
int clearInput::getPt(float *outArray)
{
int useParen;
while ((aIndex < bIndex) && isSep(buffer[aIndex])) ++aIndex; // skip seps
if ((useParen = (buffer[aIndex] == '('))) ++aIndex; // using parentheses
outArray[0] = getVRP(); // x
outArray[1] = getVRP(); // y
while ((aIndex < bIndex) && isSep(buffer[aIndex])) ++aIndex; // skip seps
if (useParen && (buffer[aIndex] == ')')) ++aIndex; // matching parenthesis
return inputError ? (inputError = 0), 0 : 1;
}
////
// grab a string from the input, make memory for it and return a pointer
////
char *clearInput::getString(int &outSize)
{
char lastQuote, *newPtr;
int stringSize;
// skip over separators
while (isSep(buffer[aIndex]) && (aIndex < bIndex)) ++aIndex;
if (aIndex >= bIndex) {
myError("couldn't find string");
outSize = 0;
return NULL;
}
if (!isQuote(buffer[aIndex])) {
myError("couldn't find quotation mark");
outSize = 0;
return NULL;
}
lastQuote = buffer[aIndex++];
for (stringSize = 0; ((aIndex + stringSize) < bIndex) &&
(lastQuote != buffer[aIndex + stringSize]); ++stringSize);
if (lastQuote != buffer[aIndex + stringSize]) {
myError("couldn't find end of quote");
outSize = 0;
return NULL;
}
newPtr = new char[stringSize + 1];
for (int i=0; i < stringSize; ++i) newPtr[i] = buffer[aIndex + i];
newPtr[i] = 0;
aIndex += stringSize + 1; // 1 for the closing quote
outSize = stringSize;
return newPtr;
}
////
// basic cgm output
////
// polygon set
////
int cgmOutput::polygonSet(const vdcPts *inPts, const int *inFlags)
{
if (!inPts || !inFlags) {
myError("no input for cgmOutput::polygonSet");
return 1;
}
vdc *myVdc;
for (int i=0; i<inPts->no(); ++i) {
myVdc = inPts->newVdc(2*i);
outVdc(myVdc);
delete myVdc;
myVdc = inPts->newVdc(2*i + 1);
outVdc(myVdc);
delete myVdc;
outType(cgmPolygonSet::typeList, inFlags[i]);
}
return 1;
}
////
// clear text output
////
int clearOutput::startCmd(baseCGM *inCGM) // start outputting the command
{
return outS(inCGM->cgmName());
}
int clearOutput::endCmd() // end the command
{
return outC(termChar) && endLine();
}
int clearOutput::outString(const char *inString) // output a CGM string
{
return outSep() && outC(quoteChar) && outS(inString) &&
outC(quoteChar);
}
// output one of a list of types
int clearOutput::outType(const char **inList, int inValue)
{
return outSep() && outS(inList[inValue]);
}
////
// input one of a list of types, assume both are in upper case
////
int clearInput::getType(const char **inList, int listSize)
{
// skip over separators
while (isSep(buffer[aIndex]) && (aIndex < bIndex)) ++aIndex;
if (aIndex >= bIndex) {
myError("couldn't find type");
return 0;
}
for (int i=0; i<listSize; ++i) {
for (int j=0; (aIndex < bIndex) && inList[i][j] &&
(inList[i][j] == buffer[aIndex + j]); ++j);
if (!inList[i][j] && !isalnum(buffer[aIndex + j])) { // found match
aIndex += j;
return i;
}
}
myError("couldn't match type ", (char *)buffer + aIndex);
return 0;
}
////
// get an integer precision
////
void clearInput::getIntPrec(intPrec *inPrec)
{
inPrec->minInt = getInt();
inPrec->maxInt = getInt();
inPrec->noBytes = 0;
}
////
// get an unsigned integer precision
////
void clearInput::getIntPrec(uIntPrec *inPrec)
{
inPrec->maxInt = getInt();
inPrec->noBytes = 0;
}
////
// get a real precision
////
void clearInput::getRealPrec(realPrec *inPrec)
{
inPrec->minReal = getReal();
inPrec->maxReal = getReal();
inPrec->noDigits = getInt();
inPrec->format = 0;
inPrec->expPart = 0;
inPrec->fractPart = 0;
}
// put an unsigned integer precision
int clearOutput::outIntPrec(uIntPrec *inPrec)
{
outInt(inPrec->maxInt);
return 1;
}
// put an integer precision
int clearOutput::outIntPrec(intPrec *inPrec)
{
outInt(inPrec->minInt);
outInt(inPrec->maxInt);
return 1;
}
// put a real precision
int clearOutput::outRealPrec(realPrec *inPrec)
{
outReal(inPrec->minReal);
outReal(inPrec->maxReal);
outInt(inPrec->noDigits);
return 1;
}
// get a real number
float clearInput::getReal()
{
const int noPowers = 21; // should be enough
static float powers[noPowers] = {1., 10., 1e2, 1e3, 1e4, 1e5, 1e6, 1e7,
1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14,
1e15, 1e16, 1e17, 1e18, 1e19, 1e20};
int i;
float fractPart = 0;
int intPart = getInt(noErrors); // get the leading integer, may not exist
float ret;
if (buffer[aIndex] == '.') {
++aIndex; // skip the period
for (i=0; isdigit(buffer[aIndex + i]); ++i); // how many digits to come
////
// renormalize the fractional part
if (i && (fractPart = getLongDecimal())) { // have a non-zero fraction
if (i<noPowers) { // easy case
fractPart /= powers[i];
} else { // maybe on some machine of the future
for (; i; --i) fractPart /= 10.0; // must be real, ULTRIX C bug
}
}
}
ret = (intPart < 0) ? intPart - fractPart : intPart + fractPart;
////
// do we have an exponent ?
if (buffer[aIndex] == 'E') { // scaled number
int exponent = getInt();
if (exponent < 0) {
if (exponent < noPowers) ret /= powers[exponent];
else for (i=0; i>exponent; --i) ret /= 10.0;
} else if (exponent > 0) {
if (exponent < noPowers) ret *= powers[exponent];
else for (i=0; i<exponent; ++i) ret *= 10.0;
}
}
// all done
return ret;
}
////
// get a cell array
////
cellArray *clearInput::getCellArray(int inColMode,
const colrValueExtent *inExtent,
const colrTable *inTable)
{
const int noPrec = 6;
static const unsigned int precValues[noPrec] = {1, 2, 4, 8, 16, 24};
long i;
vdcPts *myPts = getVdcPts(3);
int nx = getInt();
int ny = getInt();
unsigned int localColrPrec = getE(); // local colour precision
if (!localColrPrec) localColrPrec = colrPrec().maxInt; // use default
////
// will encode in binary format, find the corresponding precision
for (i=0; (i<noPrec) && (localColrPrec > ((1<<precValues[i]) - 1)); ++i);
unsigned int binaryPrec = (i<noPrec) ? precValues[i] : 32; // 32 is the max
////
// create the cellarray
cellArray *myPtr = new cellArray(inColMode, inExtent, myPts, nx, ny,
binaryPrec, 1, inTable);
////
// now get the values
long noValues;
if (inColMode) { // direct colour mode
noValues = (long)3 * nx * ny;
for (i=0; i<noValues; ++i) myPtr->addValue(getInt(skipParen));
} else {
noValues = (long)nx * ny;
for (i=0; i<noValues; ++i) myPtr->addValue(getInt(skipParen));
}
////
return myPtr;
}
////
// output a cell array
////
int clearOutput::outCellArray(cellArray *inC)
{
int ret = 1;
ret = ret && outVdcPts(inC->corners()) && outInt(inC->nx())
&& outInt(inC->ny());
// get the binary precision
unsigned int binaryPrec = inC->prec();
// find the equivalent clear text precision and output it
if (binaryPrec > (8 * sizeof(unsigned int))) {
myError("unsigned int not big enough, tell Phil !");
}
unsigned int clearPrec = (unsigned int)
(((unsigned long) 1 << binaryPrec) - 1);
ret = ret && outInt(clearPrec);
// now the values
int noValues = inC->nx() * inC->ny(); // for indexed
if (inC->colMode()) noValues *= 3; // for direct
for (int i=0; i<noValues; ++i) ret = ret && outInt(inC->getValue(i));
return ret;
}
////
// put a direct colour (R,G,B)
////
int clearOutput::outDColr(dColr &inColr)
{
// return outInt(inColr[0]) && outInt(inColr[1]) && outInt(inColr[2]);
return outInt(inColr.getValue(0)) &&
outInt(inColr.getValue(1)) && outInt(inColr.getValue(2));
}
////
// output a general colour
////
int clearOutput::outColr(genColr *inColr)
{
int ret = 1;
if (inColr->type()) { // r, g, b format
for (int i=0; i<3; ++i) ret = ret && outInt(inColr->i(i));
} else ret = outInt(inColr->i());
return ret;
}
////
// output a colour table
////
int clearOutput::outColrTable(colrTable *inTable)
{
int ret = 1;
outInt(inTable->start());
for (int i=0; i<inTable->no(); ++i) ret = ret && outDColr(inTable->val(i));
return ret;
}
////
// output a set of defaults
////
int clearOutput::outDefaults(cgmDefaults *inDefaults)
{
int ret = 1;
endCmd(); // a completely separate command in this encoding
for (baseCGM *myPtr = inDefaults->contents(); myPtr; myPtr = myPtr->next) {
myPtr->cgmOut(this);
}
outS(cgmMetafileDefaultsReplacement::endName);
return ret;
}
////
// output a single vdc
////
int clearOutput::outVdc(const vdc *inVDC)
{
return (inVDC->type()) ? outReal(inVDC->f()) : outInt(inVDC->i());
}
////
// output a set of vdc points
////
int clearOutput::outVdcPts(const vdcPts *inPts)
{
int i;
if (inPts->type()) { // real
for (i = 0; (i<inPts->no()) && outReal(inPts->fx(i)) &&
outReal(inPts->fy(i)); ++i);
} else { // integer
for (i = 0; (i<inPts->no()) && outInt(inPts->ix(i)) &&
outInt(inPts->iy(i)); ++i);
}
return i >= inPts->no(); // all successful
}
// functions to read in a clear text integer
// get an integer from the input
int clearInput::getInt(int flag)
{
int isNeg = 0, firstInt;
// may skip over separators
if (flag & skipParen) { // skip over parentheses
while ((isSep(buffer[aIndex]) || (buffer[aIndex] == '(')
|| (buffer[aIndex] == ')')) && (aIndex < bIndex)) ++aIndex;
} else if (!(flag & noSep)) { // mustn't jump over separators
while (isSep(buffer[aIndex]) && (aIndex < bIndex)) ++aIndex;
}
if (aIndex >= bIndex) {
myError("couldn't find integer");
inputError = 1;
return 0;
}
// what's our first character ?
if (buffer[aIndex] == '-') {
isNeg = 1;
++aIndex;
} else if (buffer[aIndex] == '+') ++aIndex;
else if (!isdigit(buffer[aIndex])) { // no digit ?, may be OK
if (!(flag & noErrors)) { // should get an integer
myError("no digits for getInt in", (char *)buffer);
myError("getInt read to", (char *)buffer + aIndex);
inputError = 1;
}
return 0; // return 0 in any case
}
// now guarranteed some digits
firstInt = getDecimal();
if (buffer[aIndex] == '#') { // do we have a base ?
if ((firstInt >= 2) && (firstInt <= 16)) {
return (isNeg) ? - getBased(firstInt) : getBased(firstInt);
} else {
myError("illegal base");
inputError = 1;
return 0;
}
} // bare integer
return (isNeg) ? - firstInt : firstInt;
}
// read a simple decimal integer, assume already lined up at first digit
int clearInput::getDecimal()
{
int i;
long ret = 0;
while (isdigit(buffer[aIndex])) { // should work anywhere
for (i=0; (digits[i] != buffer[aIndex]); ++i); // first matching digit
ret = 10 * ret + i;
++aIndex;
}
return (int) ret;
}
// read a simple long decimal integer, assume already lined up at first digit
long clearInput::getLongDecimal()
{
int i;
long ret = 0;
while (isdigit(buffer[aIndex])) { // should work anywhere
for (i=0; (digits[i] != buffer[aIndex]); ++i); // first matching digit
ret = 10 * ret + i;
++aIndex;
}
return ret;
}
// read a based integer
int clearInput::getBased(int inBase)
{
static char extDigits[] =
{'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
static const int maxExtend = sizeof(extDigits) / sizeof(extDigits[0]);
int ret = 0, i;
// check that we have a legal base
if ((inBase < 2) || (inBase > maxExtend)) {
myError("illegal base");
return 0;
}
// check that we have a legit number
for (i=0; (i<inBase) && (extDigits[i] != buffer[aIndex]); ++i);
if (i>=inBase) {
myError("illegal based integer");
return 0;
}
while (1) {
for (i=0; (i<inBase) && (extDigits[i] != buffer[aIndex]); ++i);
if (i>=inBase) { // no more digits
return ret;
} else { // more to go ?
ret = inBase * ret + i;
++aIndex;
}
}
}
////
// the binary input class
////
// destructor
////
binaryInput::~binaryInput() {} // keep Cray CC happy
////
// get one binary command into memory
////
#if __MSDOS__
HugePt binaryInput::getCmd()
#else
unsigned char *binaryInput::getCmd()
#endif
{
int pLen, done, bytesNeeded;
// get the next 2 non-zero bytes (skip simple, 2-byte NULLS)
do {
if (!getOffBytes(2)) {
myError("couldn't get command header");
return NULL;
}
} while (!(buffer[0] || buffer[1]));
myLastPos = pos() - 2; // mark beginning of actual command
aIndex = bIndex = 2;
////
// get the parameter length
pLen = buffer[1] & 31;
if (pLen < 31) { // short form, buffer size is guaranteed larger
// next command must start on even boundary
bytesNeeded = (pLen % 2) ? pLen + 1 : pLen;
if (bytesNeeded && !getOffBytes(bytesNeeded, bIndex)) {
myError("couldn't get command");
return NULL;
} else {
bIndex += pLen;
return buffer;
}
}
// long form
do { // carry on until we get a terminating partition header
if (!getOffBytes(2, bIndex)) { // get the next 2 bytes
myError("couldn't get partition header");
return NULL;
}
pLen = ((buffer[bIndex] & 127) << 8) | buffer[bIndex + 1];
done = !(buffer[bIndex] & 128); // finished ?
// next command must start on even boundary
bytesNeeded = (done && ((bIndex + pLen) % 2)) ? pLen + 1 : pLen;
// may need more memory
while ((bytesNeeded + bIndex) > bufferSize) {
if (!doubleBuffer(bIndex)) return NULL;
} // get bytes, maybe overwriting partition header
if (bytesNeeded && !getOffBytes(bytesNeeded, bIndex)) {
myError("couldn't get partition");
return NULL;
}
bIndex += pLen;
} while (!done);
return buffer;
}
////
// grab a string from the input, make memory for it and return a pointer
////
char *binaryInput::getString(int &outSize)
{
char *newPtr = NULL;
int i, pLen, sIndex;
unsigned int stringSize = (aIndex < bIndex)? buffer[aIndex++] : 0; // first byte has initial length
if (stringSize < 255) { // simple string
newPtr = new char[stringSize + 1];
for (i=0; i < stringSize; ++i) newPtr[i] = buffer[aIndex + i];
newPtr[i] = 0;
aIndex += stringSize;
outSize = stringSize;
return newPtr;
}
// now have complex string, get size first
int done;
stringSize = 0; // start fresh
do {
done = !(buffer[aIndex + stringSize] & 128); // finished ?
stringSize += ((buffer[aIndex + stringSize] & 127) << 8)
| buffer[aIndex + stringSize + 1];
} while (!done);
// now make the memory
newPtr = new char[stringSize + 1];
// and fill it out
sIndex = 0;
do {
done = !(buffer[aIndex] & 128); // finished ?
pLen = ((buffer[aIndex] & 127) << 8) | buffer[aIndex + 1];
aIndex += 2;
for (i=0; i<pLen; ++i) newPtr[sIndex++] = buffer[aIndex++];
} while (!done);
if (sIndex != stringSize) myError("bad string");
newPtr[sIndex] = 0;
outSize = stringSize;
return newPtr;
}
////
// diagnostic
////
const char *binaryInput::cmdSignature()
{
static char myString[60];
sprintf(myString, "(%d, %d) = (%d, %d)", (int) buffer[0], (int) buffer[1],
bufferClass(), bufferElement());
return myString;
}
////
// general signed integer (assume long at least 4 bytes, may truncate)
////
int binaryInput::gInt(int noBytes)
{
long ret = (buffer[aIndex] & 128) ? (-1 ^ 255) | (int) buffer[aIndex++]
: buffer[aIndex++];
switch(noBytes) {
case 4:
ret = (ret<<8) | buffer[aIndex++]; // fallthru
case 3:
ret = (ret<<8) | buffer[aIndex++]; // fallthru
case 2:
ret = (ret<<8) | buffer[aIndex++]; // end
}
return (int) ret;
}
////
// general shifted signed integer
////
int binaryInput::gShiftInt(int noBytes, int bitsRead)
{
// for convenience/speed
static unsigned char bitMask[8] = {255, 127, 63, 31, 15, 7, 3, 1};
//
if ((bitsRead > 7) || (bitsRead < 0)) {
myError("illegal bitsRead");
return 0;
}
if (bitsRead == 0) return gInt(noBytes); // no shift
// span parts of noBytes + 1 bytes
//
// spans at least 2 bytes, get 'em one at a time
// first byte
// get the sign
long ret = ((buffer[aIndex] & (1 << (7 - bitsRead))) ? -1 : 0)
<< (7 - bitsRead);
// now the rest of the bits
ret = ret | (buffer[aIndex++] & bitMask[bitsRead]);
switch(noBytes) {
case 4:
ret = (ret<<8) | buffer[aIndex++]; // fallthru
case 3:
ret = (ret<<8) | buffer[aIndex++]; // fallthru
case 2:
ret = (ret<<8) | buffer[aIndex++]; // end
}
// last byte
ret = (ret << bitsRead) | (buffer[aIndex] >> (8 - bitsRead));
return ret;
}
////
// general unsigned integer
////
unsigned int binaryInput::gUInt(int noBytes)
{
unsigned long ret = buffer[aIndex++];
switch(noBytes) {
case 4:
ret = (ret<<8) | (buffer[aIndex++] & 255); // fallthru
case 3:
ret = (ret<<8) | (buffer[aIndex++] & 255); // fallthru
case 2:
ret = (ret<<8) | (buffer[aIndex++] & 255); // end
}
return (unsigned int) ret;
}
////
// figure out how many points we have coming
////
int binaryInput::getNoPts()
{
if (aIndex >= bIndex) {
myError("no Pts to get");
return 0;
}
// each vdc uses an even number of bytes, 2 vdc's per point (8/2 = 4)
if (myVdcType()) { // real vdc's
return ((bIndex - aIndex) * 4) /
(vdcRealPrec().expPart + vdcRealPrec().fractPart);
} else return (bIndex - aIndex) / (2 * vdcIntPrec().noBytes);
}
////
// figure out how many points we have in a polygon set
////
int binaryInput::polygonSetSize()
{
if (aIndex >= bIndex) {
myError("no polygon set Pts to get");
return 0;
}
// each vdc uses an even number of bytes, 2 vdc's per point (8/2 = 4)
// the enumerated flag takes 2 bytes
if (myVdcType()) { // real vdc's
return ((bIndex - aIndex) * 4) /
(vdcRealPrec().expPart + vdcRealPrec().fractPart + 8);
} else return (bIndex - aIndex) / (2 * vdcIntPrec().noBytes + 2);
}
////
// get one real vdc pt
////
int binaryInput::getPt(float *inF)
{
if (aIndex >= bIndex) return 0;
inF[0]=getVRP();
if (aIndex >= bIndex) return 0;
inF[1]=getVRP();
return (aIndex > bIndex) ? 0 : 1;
}
////
// get one integer vdc pt
////
int binaryInput::getPt(int *inI)
{
if (aIndex >= bIndex) return 0;
inI[0]=getVIP();
if (aIndex >= bIndex) return 0;
inI[1]=getVIP();
return (aIndex > bIndex) ? 0 : 1;
}
////
// general fixed point real
////
float binaryInput::gFX(realPrec &inPrec)
{
double expPart = gInt(inPrec.expPart/8);
double fractPart = gUInt(inPrec.fractPart/8);
float ret = expPart + fractPart / ((long) 1 << inPrec.fractPart);
return ret;
}
////
// general floating point real
////
float binaryInput::gFP(realPrec &inPrec)
{
static double p149 = 1, p23 = 1, p1074, p52;
double dfract;
unsigned int exponent;
unsigned long fract;
float ret;
int i;
if (p149 == 1) for (i=0; i<149; ++i) p149 *= 2.0; // initialize
if (p23 == 1) for (i=0; i<23; ++i) p23 *= 2.0; // initialize
if (p1074 == 1) for (i=0; i<1074; ++i) p1074 *= 2.0; // initialize
if (p52 == 1) for (i=0; i<p52; ++i) p52 *= 2.0; // initialize
int signBit = (buffer[aIndex] >> 7) & 1; // is this negative ?
// which precision is this ?
switch (inPrec.fractPart + inPrec.expPart) {
case 32: // 32 bit precision
// get the exponent
exponent = ((buffer[aIndex] & 127) << 1) + ((buffer[aIndex + 1] >> 7) & 1);
// get the fractional part
fract = ((unsigned long)(buffer[aIndex + 1] & 127) << 16) +
((unsigned long)buffer[aIndex + 2] << 8)
+ buffer[aIndex + 3];
// step forward the pointer before we forget
aIndex += 4;
// check for special cases
if (exponent == 255) {
if (fract == 0) { // big number
return (signBit) ? -MAXFLOAT : MAXFLOAT;
} else { // screwed up
myError("undefined IEEE number");
return 0;
}
} else if (exponent == 0) {
if (fract == 0) return 0;
else return (signBit) ? -fract / p149 : fract / p149; // fract / 2^149
} else { // normal number
ret = 1 + fract / p23;
if (exponent < 127) for (i=0; i<(127-exponent); ++i) ret /= 2.0;
else if (exponent > 127) for (i=0; i<(exponent-127); ++i) ret *= 2.0;
return (signBit) ? -ret : ret;
}
break;
case 64: // 64 bit precision !!! not for PC
exponent = ((buffer[aIndex] & 127) << 4) + ((buffer[aIndex+1] >> 4) & 15);
// fractional [part might not fit in a long
dfract = buffer[aIndex + 1] & 15;
for (i=2; i<8; ++i) {
dfract *= 256.0;
dfract += buffer[aIndex + i];
}
// step forward the pointer before we forget
aIndex += 8;
if (exponent == 2047) {
if (fract == 0) { // big number
return (signBit) ? -MAXFLOAT : MAXFLOAT;
} else { // screwed up
myError("undefined IEEE number");
return 0;
}
} else if (exponent == 0) {
if (fract == 0) return 0;
else return (signBit) ? -fract / p1074 : fract /p1074; // fract / 2^1074
} else { // normal number
ret = 1 + dfract / p52;
if (exponent < 1023) {
for (i=0; i<(1023 - exponent); ++i) ret /= 2.0;
} else if (exponent > 1023) {
for (i=0; i<(exponent - 1023); ++i) ret *= 2.0;
return (signBit) ? -ret : ret;
} else return 0; // screwed up
}
break;
}
return 0; // for safety
}
////
// get a real precision
////
void binaryInput::getRealPrec(realPrec *inPrec)
{
char myString[60];
int format = getE();
int expPart = getInt();
int fractPart = getInt();
// check for legality
if ((((fractPart + expPart) != 32) && ((fractPart + expPart) != 64)) ||
((format != 0) && (format != 1)) ||
((format == 0) && ((fractPart != 9) && (fractPart != 23))) ||
((format == 1) && ((fractPart != 16) && (fractPart != 32)))) {
sprintf(myString, "(%d, %d, %d)", format, expPart, fractPart);
myError("illegal binary real precision", myString);
return;
}
////
inPrec->format = format;
inPrec->expPart = expPart;
inPrec->fractPart = fractPart;
inPrec->minReal = - 1 << expPart; // guess
inPrec->maxReal = 1 << expPart; // guess
}
////
// NCAR specific input
////
// initialization
////
void NCARInput::initialize()
{
if (!fillLocalBuffer()) myError("couldn't get first NCAR block");
}
////
// get some bytes
////
int NCARInput::getOffBytes(unsigned int noBytes, unsigned long offset)
{
for (int i=0; i<noBytes; ++i) {
while ((endIndex <= startIndex) && fillLocalBuffer()); // may need bytes
if (endIndex <= startIndex) {
myError("couldn't get NCAR data");
return 0;
} else buffer[offset + i] = localBuffer[startIndex++];
}
return 1;
}
////
// fill the local buffer
////
int NCARInput::fillLocalBuffer()
{
if (!getBytes(NCARSIZE, localBuffer)) {
myError("couldn't get NCAR block");
return 0;
}
startIndex = 4; // start of real data
endIndex = startIndex + ((localBuffer[0] << 8) | (localBuffer[1] & 255));
if (endIndex % 2) ++endIndex; // sometimes NCAR doesn't include pad byte
if (endIndex > NCARSIZE) {
char myString[20];
sprintf(myString, "%d bytes", endIndex - startIndex);
myError("too many bytes in NCAR header", myString);
return 0;
} else return 1;
}
////
// get a cell array
////
cellArray *binaryInput::getCellArray(int inColMode,
const colrValueExtent *inExtent,
const colrTable *inTable)
{
char myString[60];
long i;
vdcPts *myPts = getVdcPts(3);
int nx = getInt();
int ny = getInt();
unsigned int localColrPrec = getE(); // local colour precision
if (!localColrPrec) localColrPrec = colrPrec().noBytes * 8; // use default
////
// create the cellarray
cellArray *myPtr = new cellArray(inColMode, inExtent, myPts, nx, ny,
localColrPrec, 1, inTable);
// what mode is this ?
int repMode = getE();
////
// now get the values
int valSize = (inColMode) ? 3 : 1;
int valBits = valSize * localColrPrec;
int noValues = valSize * nx;
int rowSize = 2 * ((noValues * localColrPrec + 15) / 16); // padded
if (repMode) { // packed list
for (i=0; i<ny; ++i) {
if ((aIndex + rowSize) > bIndex) {
myError("not enough bytes for cell array");
break;
}
// add a complete row
myPtr->addValues(&buffer[aIndex], 0, noValues);
aIndex += rowSize;
}
} else { // run length encoded
int runCount, valsGot, j, bitsGot;
for (i=0; i<ny; ++i) { // rows start on a 2-byte boundary
bitsGot = valsGot = 0;
while (valsGot < nx) {
runCount = getShiftInt(bitsGot); // increases aIndex
if (((runCount + valsGot) > nx) || (runCount < 0)) {
sprintf(myString, "%d, x = %d, nx = %d, y = %d, ny = %d",
runCount, valsGot, nx, i, ny);
myError("illegal runcount in cell array", myString);
return myPtr;
} // else OK, replicate value
for (j=0; j<runCount; ++j)
myPtr->addValues(&buffer[aIndex], bitsGot, valSize);
valsGot += runCount;
bitsGot += valBits;
if (bitsGot > 7) { // step forward the byte index
aIndex += bitsGot / 8;
bitsGot = bitsGot % 8;
}
}
if (aIndex > bIndex) {
myError("not enough bytes for run length encoding");
return myPtr;
}
if (bitsGot) ++aIndex; // start at a clean byte
if (aIndex % 2) ++aIndex; // pad at end of rows
}
}
////
return myPtr;
}
#ifdef macintosh
#pragma segment CIO2
#endif
////
// parsing initialization
////
// set the parser's pointer
////
cgmNameNew *cgmInput::cgmNameArray = NULL;
////
// add new classes to this array later so that the parser knows about them
////
// define an INITMACRO set up for runtime initialization
////
#define INITMACRO(inName) \
cgmNameArray[i].myName = &inName::myName;\
cgmNameArray[i].myClass = inName::myClass;\
cgmNameArray[i].myElement = inName::myElement;\
cgmNameArray[i].fp = inName::getNew; ++i;
////
// now fill out the structure, either at runtime
////
void cgmInput::initNameArray() {
////
// grab some memory
cgmNameArray = new cgmNameNew[cgmNoClasses];
if (!cgmNameArray) myError("couldn't create parsing array", "", 0);
int i = 0;
////
// delimiters
INITMACRO(cgmBeginMetafile)
endMetafileIndex = i; // will need this later
INITMACRO(cgmEndMetafile)
beginPictureIndex = i; // will need this later
INITMACRO(cgmBeginPicture)
INITMACRO(cgmBeginPictureBody)
INITMACRO(cgmEndPicture)
// metafile descriptors
INITMACRO(cgmMetafileVersion)
INITMACRO(cgmMetafileDescription)
INITMACRO(cgmVdcType)
INITMACRO(cgmIntegerPrec)
INITMACRO(cgmRealPrec)
INITMACRO(cgmIndexPrec)
INITMACRO(cgmColrPrec)
INITMACRO(cgmColrIndexPrec)
INITMACRO(cgmMaxColrIndex)
INITMACRO(cgmColrValueExtent)
INITMACRO(cgmMetafileElementList)
INITMACRO(cgmMetafileDefaultsReplacement)
INITMACRO(cgmFontList)
INITMACRO(cgmCharacterSetList)
INITMACRO(cgmCharacterCodingAnnouncer)
// picture descriptors
INITMACRO(cgmScalingMode)
INITMACRO(cgmColrMode)
INITMACRO(cgmLineWidthMode)
INITMACRO(cgmMarkerSizeMode)
INITMACRO(cgmEdgeWidthMode)
INITMACRO(cgmVdcExtent)
INITMACRO(cgmBackgroundColr)
// control elements
INITMACRO(cgmVdcInteger)
INITMACRO(cgmVdcReal)
INITMACRO(cgmAuxColr)
INITMACRO(cgmTransparency)
INITMACRO(cgmClipRect)
INITMACRO(cgmClip)
// graphical primitives
INITMACRO(cgmPolyline)
INITMACRO(cgmDisPolyline)
INITMACRO(cgmPolymarker)
INITMACRO(cgmText)
INITMACRO(cgmRestrText)
INITMACRO(cgmApndText)
INITMACRO(cgmPolygon)
INITMACRO(cgmPolygonSet)
INITMACRO(cgmGDP)
INITMACRO(cgmCellArray)
INITMACRO(cgmRectangle)
INITMACRO(cgmCircle)
INITMACRO(cgmArc3Pt)
INITMACRO(cgmArc3PtClose)
INITMACRO(cgmArcCtr)
INITMACRO(cgmArcCtrClose)
INITMACRO(cgmEllipse)
INITMACRO(cgmEllipArc)
INITMACRO(cgmEllipArcClose)
// attributes
INITMACRO(cgmLineIndex)
INITMACRO(cgmLineType)
INITMACRO(cgmLineWidth)
INITMACRO(cgmLineColr)
INITMACRO(cgmMarkerIndex)
INITMACRO(cgmMarkerType)
INITMACRO(cgmMarkerSize)
INITMACRO(cgmMarkerColr)
INITMACRO(cgmTextIndex)
INITMACRO(cgmFontIndex)
INITMACRO(cgmTextPrec)
INITMACRO(cgmCharExpan)
INITMACRO(cgmCharSpace)
INITMACRO(cgmTextColr)
INITMACRO(cgmCharHeight)
INITMACRO(cgmCharOri)
INITMACRO(cgmTextPath)
INITMACRO(cgmTextAlign)
INITMACRO(cgmCharSetIndex)
INITMACRO(cgmAltCharSetIndex)
INITMACRO(cgmFillIndex)
INITMACRO(cgmHatchIndex)
INITMACRO(cgmPatIndex)
INITMACRO(cgmIntStyle)
INITMACRO(cgmFillColr)
INITMACRO(cgmEdgeIndex)
INITMACRO(cgmEdgeType)
INITMACRO(cgmEdgeWidth)
INITMACRO(cgmEdgeColr)
INITMACRO(cgmEdgeVis)
INITMACRO(cgmFillRefPt)
INITMACRO(cgmPatTable)
INITMACRO(cgmPatSize)
INITMACRO(cgmColrTable)
INITMACRO(cgmASF)
// escape element
INITMACRO(cgmEscapeElement)
// externals
INITMACRO(cgmMessage)
INITMACRO(cgmApplData)
};
#undef INITMACRO
////
// binary output
////
int binaryOutput::startCmd(baseCGM *inCGM) // start outputting the command
{
return 1; // fix later
}
int binaryOutput::endCmd() // end the command
{
return 1; // fix later
}
int binaryOutput::outString(const char *inString) // output a CGM string
{
return 1; // fix later
}
// output one of a list of types
int binaryOutput::outType(const char **inList, int inValue)
{
return 1; // fix later
}